module jinji.tag.api;

import jinji.common.model;
import jinji.common.query;
import jinji.tag.model;
import jinji.tag.service,
jinji.util.string;

extern (C):

mixin getObject!(Tag, "getTag", "查询标签", "标签", "name");

mixin getObject!(TagAlias, "getTagAlias", "查询别名", "别名", "name");

mixin getObject!(TagCategory, "getTagCategory", "查询标签类别", "标签类别", "name");

mixin getObject!(TagGroup, "getTagGroup", "查询标签组", "标签组", "name");

mixin getObject!(TagImplications, "getImplication", "查询隐含标签", "隐含标签", "name");

mixin getObject!(TAVisibility, "getTAVisibility", "查询标签别名可见性", "标签别名可见性", "updated_at desc");

mixin getObject!(TGVisibility, "getTGVisibility", "查询标签互斥组可见性", "标签互斥组可见性", "updated_at desc");

mixin getObject!(TIVisibility, "getTIVisibility", "查询隐含标签可见性", "隐含标签可见性", "updated_at desc");

/// 获取标签数增量
@"标签数增量"@type("number[]")
@Action void getTagCountDelta(ref Request req, @"标签串" string tags) {
	foreach (tag; Splitter(tags)) {
		auto q = query!(SB.select!(TagCountDelta.delta)
				.where("name=$1"))(tag);
		req.send(q.get(0L));
	}
}

/// 自动完成
@"标签列表"@type("string[]")
@Action void autocmpl(ref Request req,
	@"标签名" string str, @"标签类别" string category = "", @"最大数量"uint limit = 20) {
	checkArgRange(str.stringof, str.length >= 2 && str.length <= maxTagLength, "输入长度不合法");

	auto r = fixedBuf!(maxTagLength * 2, "输入过长");
	escapeTag(str, r);
	r ~= '%';
	enum sql = SB.select!(Tag.name);
	auto q = category.length ?
		query!(sql.where(`name like $1 ESCAPE '\' AND category=$2`)
				.orderBy(`"count" desc`)
				.limit("$3"))(r.data, category, limit) : query!(sql.where(`name like $1 ESCAPE '\'`)
				.orderBy(`"count" desc`).limit("$2"))(r.data, limit);
	foreach (s; q)
		req.send(s.get!string);
}

/// 添加/修改/删除标签
@"删除数量"@type("[number]")
@Action void setTag(ref Request req, @"ID"long id, @"名称" string name,
	@"类别" string category = defCategory, @"标签组" string group = "") {
	Tag tag;
	if (id) {
		auto q = query!(SB.select!Tag.where("id=$1"))(parseId(id));
		tag = q.get(Tag());
		req.checkPerm(tag.creator, Perm.editTag);
	}

	if (name.length) {
		checkArg(category.stringof, has!(TagCategory, "name=", category),
			text("标签类别'", category, "'不存在"));

		tag.name = parseTag(name);
		tag.category = parseName(category);
		tag.group = group.length ? parseTags(group) : Tags.empty;
		if (!tag.creator)
			tag.creator = req.uid;
		const time = now;
		if (!tag.created_at)
			tag.created_at = time;
		tag.updated_at = time;
		db.replaceInto(tag);
	} else {
		auto q = query!(SB.select!(Tag.name)
				.where("id=$1"))(id);
		checkArg(id.stringof, !q.empty, "标签不存在");
		checkArg(id.stringof, tagCount(q.get!string) == 0, "标签已被使用");
		req.send(db.delWhere!(Tag, "id=$1")(id));
	}
}

/// 导入标签
@"导入标签数"@type("number")
extern (D) @Action void importTags(ref Request req, @"标签串" string tags,
	@"类别" string category = defCategory, @"标签组" string group = "") {
	import std.meta,
	tame.string;

	req.require(Perm.editTag);
	req.send(jinji.tag.service.importTags(tags,
			parseName(category), parseTags(group), req.uid));
}

/// 导出标签
@"标签串"@type("string")
@Action void exportTags(ref Request req) {
	import tame.buffer;

	StringSink r;
	jinji.tag.service.exportTags(r);
	req.send(r[]);
}

/// 更新标签的使用数
@Action void updateTagCount(ref Request req) {
	updateCount();
}

/// 解析别名
@"原名"@type("string[]")
@Action void resolveAliases(ref Request req, @"标签串" string tags) {
	checkArg(tags.stringof, tags.length <= 1024, "标签串过长");
	foreach (tag; Splitter(tags))
		req.send(resolve(tag));
}

/// 添加/修改/删除标签别名
@"删除数量"@type("[number]")
@Action void setTagAlias(ref Request req, @"ID"long id, @"别名" string name,
	@"原名" string to, @"描述" string desc = "") {
	req.require(Perm.editTA);
	req.modify!TagAlias(parseId(id), parseTag(name, true),
		parseAliases(name, to), parseDesc(desc), req.uid, now);
}

/// 添加/修改/删除标签类别
@"删除数量"@type("[number]")
@Action void setTagCategory(ref Request req, @"名称" string name, @"父类别" string parent = null,
	@"描述" string desc = "", @"样式" string style = "") {
	req.require(Perm.editTC);
	// TODO: check parent
	req.modify!TagCategory(parseName(name), trust!Name(parent),
		parseDesc(desc), parseDesc(style), req.uid, now);
}

/// 添加/修改/删除标签组
@"删除数量"@type("[number]")
@Action void setTagGroup(ref Request req, @"ID"long id,
	@"名称" string name, @"描述" string desc = "") {
	req.require(Perm.editTG);
	req.modify!TagGroup(parseId(id), parseName(name), parseDesc(desc), req.uid, now);
}

/// 添加/修改/删除隐含标签
@"删除数量"@type("[number]")
@Action void setImplication(ref Request req, @"ID"long id,
	@"标签名" string name, @"隐含标签" string implies, @"描述" string desc = "") {
	req.require(Perm.editTI);
	req.modify!TagImplications(parseId(id), parseTag(name, true),
		parseImplies(name, implies), parseDesc(desc), req.uid, now);
}

/// 为帖子添加/删除标签
@"变更请求id"@type("[number]")
@Action void tag(ref Request req, @"帖子id"long pid, @"标签串" string tags,
	@"标题" string title = "", @"描述" string desc = "") {
	import jinji.post.cr;

	req.require(Perm.editPost);
	req.send(requestChange(req.uid, parseId(pid), tags,
			parseText!"标题"(title), parseDesc(desc)));
}

/// 获取标签总使用数
@"获取标签总使用数"@type("number")
@Action void getTotalTagCount(ref Request req) {
	const sum = query!(SB.select!"ifnull(sum(count),0)"
			.from!Tag()).get!long;
	const delta = query!(SB.select!"ifnull(sum(delta),0)"
			.from!TagCountDelta()).get!long;
	req.send(sum + delta);
}

/// 获取相关标签
@"相关标签"@type("string[]")
@Action void getRelatedTags(ref Request req, @"标签串" string tags, @"数量"int count = 10) {
	count = min(count, 20);
	foreach (r; relatedTags(tags, count))
		req.send(r.get!string);
}
